﻿// Inner Fire 游戏引擎库
// AnimatorTransforms - 动画机变换矩阵列表
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于临时保存一个变换矩阵，然后用于最后的混合。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-05-16

#pragma once

#include <DirectXMath.h>
#include <EASTL/vector.h>
#include <memory>
#include <graphics/transform_def.h>
#include <game/animation/root_motion.h>
#include <game/animation/animation_clip.h>

namespace ifire::game {
class Snapshot {
public:
  Snapshot(int index, size_t bone_count);
  Snapshot(const Snapshot& lhs) = delete;
  Snapshot& operator=(const Snapshot& lhs) = delete;
  ~Snapshot() = default;

  friend class RootMotion;

  // 将两个项目按权重混合，配置到本项目中
  void Mix(const Snapshot& a, const Snapshot& b);
  // 设置当前的播放信息
  void SetCurrent(AnimationClip* clip, float frame);
  // 提取动作中的RootMotion
  void ExecuteRootMotion(IMat& mat);
  // 不使用RootMotion
  void PassRootMotion();

  // 是否已经使用
  inline bool IsUsed() const { return is_used_; }
  // 设置为使用
  inline void SetUsed(bool value) { is_used_ = value; }
  // 获得RootMotion的Delta
  inline IVec GetDelta() const { return root_motion.GetDelta(); }
  inline void SetDelta(IVec vec) { root_motion.SetDelta(vec); }
  

public:
  // 当前此Snapshot对应的动画（如果改变，需要有重置的逻辑）
  AnimationClip* clip;
  // 当前动画正播放的帧
  float frame;
  // 此位置的权重
  float weight;
  // 此对象的矩阵
  MatrixList transforms;
  // 此项目的RootMotion
  RootMotion root_motion;


private:
  // 此项目的索引
  int index_;
  // 标记此对象是否使用
  bool is_used_;
  // 此对象的骨骼数量
  size_t bone_count_;
};

using SnapshotsPtr = std::unique_ptr<Snapshot>;

class Snapshots {
public:
  Snapshots(size_t bone_count);
  Snapshots(const Snapshots& lhs) = delete;
  Snapshots& operator=(const Snapshots& lhs) = delete;
  ~Snapshots() = default;

  // 获取一个Slot，如果没有，则创建
  Snapshot& Get(int slot);
  // 清空项目，将所有项目都设置为不使用
  void ClearUsed();
  // 使用权重进行混合，A和B指定项目，store指定要保存的位置
  void Mix(int a_index, int b_index, int store_index);
  // 将一个项目提取到Mix。如果不指定to_index，默认提取到第一项。
  void Pick(int from_index, int to_index = 0);
  // 获得已经使用的项目
  size_t GetUsedCount();

  // 获得第一个项目，通常最终结果就放在第一个项目中
  Snapshot& GetPrimary() { return *items_[0].get(); }

  // 当前项目的大小
  size_t size() { return items_.size(); }

private:
  // 对象的Node数量，新建项目的时候会用到。
  size_t bone_count_;
  // 保存的Transform列表
  eastl::vector<SnapshotsPtr> items_;
};

} // namespace ifire::game